package com.my.iot.protocol.modbus.tcp;

import com.my.iot.protocol.modbus.tcp.entity.ModbusDTO;
import com.my.iot.protocol.modbus.tcp.enums.ModbusDataType;
import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.locator.BaseLocator;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wangjixin
 */
@Component
public class ModbusTcpReadAndWrite {

    @Resource
    private ModbusTcpConnect modbusTcpConnect;

    /**
     * BaseLocator：用于定义如何定位和读取 Modbus 寄存器数据，是一个抽象类，提供了多种静态工厂方法来创建具体的定位器实例。
     * 读写操作：实际的读写操作是由 ModbusMaster 或 ModbusSlave 类中的方法来完成的，BaseLocator 只是作为参数传递给这些方法，以指定读写的具体位置和数据类型。
     */


    /**
     * 读取单个点位
     *
     * @param host    主机地址
     * @param port    端口号
     * @param slaveId 从站ID
     * @param offset  点位偏移量
     * @return 点位的值
     * @throws ModbusTransportException 如果读取失败
     */
    public Number readPoint(String host, int port, int slaveId, int offset) throws ModbusTransportException, ErrorResponseException {
        String key = host + ":" + port;
        ModbusMaster master = modbusTcpConnect.getTcpMasters().get(key);
        if (master == null) {
            throw new IllegalArgumentException("Modbus master not found for " + key);
        }
        BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, 0x02);
        return master.getValue(locator);
    }
//
//    /**
//     * 写入单个点位
//     *
//     * @param host     主机地址
//     * @param port     端口号
//     * @param slaveId  从站ID
//     * @param offset   点位偏移量
//     * @param value    要写入的值
//     * @param dataType 数据类型（例如，ModbusDataType.HOLDING_REGISTER）
//     * @throws ModbusTransportException 如果写入失败
//     */
//    public void writePoint(String host, int port, int slaveId, int offset, int value, ModbusDataType dataType) throws ModbusTransportException, ErrorResponseException {
//        String key = host + ":" + port;
//        ModbusMaster master = modbusTcpConnect.getTcpMasters().get(key);
//        if (master == null) {
//            throw new IllegalArgumentException("Modbus master not found for " + key);
//        }
//
//        BaseLocator<Integer> locator = (BaseLocator<Integer>) createLocator(slaveId, offset, dataType);
//
//        master.setValue(locator, value);
//    }
//

    /**
     * 批量读取点位
     *
     * @return 点位的值映射
     * @throws ModbusTransportException 如果读取失败
     */

    public Map<Integer, Object> readPoints(ModbusDTO dto) throws ModbusTransportException, ErrorResponseException {

        // 输入验证
        List<Integer> offsets = dto.getOffset();
        if (null == offsets || offsets.isEmpty()) {
            return null;
        }

        // 配置化IP和端口
        final String ipAddress = "192.168.124.49";
        final int port = 502;
        String key = ipAddress + ":" + port;

        // 获取ModbusMaster对象
        ModbusMaster master = modbusTcpConnect.getTcpMasters().get(key);
        if (null == master) {
            throw new IllegalArgumentException("Modbus master not found for " + key);
        }
        // 创建BatchRead对象
        BatchRead<Integer> batch = new BatchRead<>();

        for (Integer item : offsets) {
            BaseLocator<Boolean> locator = BaseLocator.coilStatus(dto.getSlaveId(), item);
            batch.addLocator(item, locator);
        }

        BatchResults<Integer> send = master.send(batch);

        Map<Integer, Object> result = new HashMap<>();
        for (Integer item : offsets) {
            result.put(item, send.getValue(item));
        }

        return result;
    }


//
//    /**
//     * 批量写入点位
//     *
//     * @param host     主机地址
//     * @param port     端口号
//     * @param slaveId  从站ID
//     * @param values   点位偏移量和值的映射
//     * @param dataType 数据类型（例如，ModbusDataType.HOLDING_REGISTER）
//     * @throws ModbusTransportException 如果写入失败
//     */
//    public void writePoints(String host, int port, int slaveId, Map<Integer, Integer> values, ModbusDataType dataType) throws ModbusTransportException, ErrorResponseException {
//        String key = host + ":" + port;
//        ModbusMaster master = modbusTcpConnect.getTcpMasters().get(key);
//        if (master == null) {
//            throw new IllegalArgumentException("Modbus master not found for " + key);
//        }
//
//        for (Map.Entry<Integer, Integer> entry : values.entrySet()) {
//            int offset = entry.getKey();
//            int value = entry.getValue();
//            BaseLocator<Integer> locator = (BaseLocator<Integer>) createLocator(slaveId, offset, dataType);
//            master.setValue(locator, value);
//        }
//    }
//

    /**
     * 根据数据类型创建相应的 BaseLocator
     *
     * @param slaveId  从站ID
     * @param offset   点位偏移量
     * @param dataType 数据类型
     * @return BaseLocator 实例
     */
    private BaseLocator<?> createLocator(int slaveId, int offset, ModbusDataType dataType) {
        switch (dataType) {
            case HOLDING_REGISTER:
                return BaseLocator.holdingRegister(slaveId, offset, 0x02);
            case INPUT_REGISTER:
                return BaseLocator.inputRegister(slaveId, offset, 0x02);
            case COIL_STATUS:
                return BaseLocator.coilStatus(slaveId, offset);
            case DISCRETE_INPUT:
                // 使用 coilStatus 作为替代
                return BaseLocator.coilStatus(slaveId, offset);
            default:
                throw new IllegalArgumentException("Unsupported data type: " + dataType);
        }
    }


}


